/*******************************************************************************
 * FILE NAME          : transport_main.c
 *
 * DESCRIPTION        : This file provides the functions handle for Linked-list
 *                      .This file contains following function definitions.
 *                      syslog_alloc()
 *                      syslog_dealloc()
 *
 * DESIGN REFERENCE   :
 *
 * STARTING VERSION:
 *
 *
 * REVISION HISTORY   :
 * Date            Author                   REASON
 * 06.08.2013    Thuan Nguyen           Creation and Coding
 * ****************************************************************************/
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<pthread.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include"../h/tp_types.h"
#include"../h/logging.h"
#include"../h/tp_linked_list_def.h"
#include"../h/syslog_api_platform.h"
#include"../h/syslog_api_platform.h"
extern threads_transport_t *g_threads_list;
extern pthread_mutex_t g_thread_list_mutex;

U8 tp_init_master_thread_func();
U8 tp_slave_thread_handle_func(thread_info_t *thread_info);
void tp_master_thread_handler_func(thread_info_t *thread_data);
U8 tp_create_slave_thread_func(U8 socket_id,struct sockaddr_in *client_addr);
U8 tp_rm_slave_thread_func();
U8 tp_init_listenning_thread_func();
U8 tp_listening_thread_handle_func(threads_transport_t *thread_data);
U8 initialization_func();
/***********************************************************************
 * FUNCTION NAME: 
 *  initialization_func
 * DESCRIPTION: initial all global variable and other initialization.
 *
 * INPUT: 
 *	
 * OUTPUT:
 *	
 * RETURN:
 *	val_result
 * GLOBAL DATA REFERRED:
 *
 * CALLED ROUTINES:
 *
 * NOTES:
 *
 ************************************************************************/
U8 initialization_func()
{
	U8 val_result;
	U8 res;
	res = pthread_mutex_init(&g_thread_list_mutex,NULL);
	if(SYSLOG_SUCCESS!=res)
	{
		SYSLOG_TRANSPORT_ERROR_LOGGING("Mutex Initialization failure!");
		exit(EXIT_FAILURE);
	}
	return val_result;
}
/***********************************************************************
 * FUNCTION NAME: 
 *  tp_init_master_thread_func
 * DESCRIPTION: Send request to tasklist queues.
 *
 * INPUT: 
 *	request_msg_t *req_msg
 * OUTPUT:
 *	
 * RETURN:
 *	val_result
 * GLOBAL DATA REFERRED:
 *
 * CALLED ROUTINES:
 *
 * NOTES:
 *
 ************************************************************************/
U8 tp_init_master_thread_func()
{
	U8 val_result = SYSLOG_FALSE;
	pthread_t thread_key;
	void *temp_thread_result;
	threads_transport_t *temp_thread_node = SYSLOG_NULL;
	
	/*Create a Node on linked-list and this Node will be parameter of function handle of master function*/
	temp_thread_node = tp_add_empty_item_to_ll_func(g_threads_list);
	if(SYSLOG_NULL == temp_thread_node)
	{
			SYSLOG_TRANSPORT_ERROR_LOGGING("Can't Add a Node to g_threads_list.");
			return val_result;
	}
	else
	{
		val_result = pthread_create(&thread_key,NULL,(void*)tp_master_thread_handler_func \
								,temp_thread_node);
		if(SYSLOG_SUCCESS != val_result)
		{
			SYSLOG_TRANSPORT_ERROR_LOGGING("Can't create slave thread");
			tp_rm_empty_item_from_ll_func(g_threads_list,temp_thread_node);
			val_result = SYSLOG_FALSE;
		}
		else
		{
			temp_thread_node->data_thread.thread_type = MASTER_THREAD_TYPE;
			temp_thread_node->data_thread.thread_key = thread_key;
			temp_thread_node->data_thread.thread_func = (void*)tp_master_thread_handler_func;
			temp_thread_node->state_thread = ITEM_STATE_ACTIVE;
		}

	}

	/*Join master thread*/
	val_result = pthread_join(thread_key,&temp_thread_result);
	if(SYSLOG_SUCCESS != val_result)
	{
		val_result = SYSLOG_FALSE;
		SYSLOG_TRANSPORT_ERROR_LOGGING("Join thread master failure.");
	}
	return val_result;
}
/***********************************************************************
 * FUNCTION NAME: 
 *  tp_create_slave_thread_func
 * DESCRIPTION: 
 * 	create slave thread for a connection. This connection will handle all
 *  transfer data corresponding port and ip_address.
 *
 * INPUT: 
 *	socket_id
 *	client_addr
 *
 * OUTPUT:
 *	
 * RETURN:
 *	val_result
 * GLOBAL DATA REFERRED:
 *
 * CALLED ROUTINES:
 *
 * NOTES:
 *
 ************************************************************************/
U8 tp_create_slave_thread_func(U8 socket_id,struct sockaddr_in *client_addr)
{
	U8 val_result = SYSLOG_FALSE;
	pthread_t thread_key;
	void *temp_thread_result;
	threads_transport_t *temp_thread_node = SYSLOG_NULL;
	thread_info_t thread_info;

	/*Create a Node on linked-list and this Node will be parameter of slave function*/
	temp_thread_node = tp_add_empty_item_to_ll_func(g_threads_list);
	if(SYSLOG_NULL == temp_thread_node)
	{
		SYSLOG_TRANSPORT_ERROR_LOGGING("Can't Add a Node to g_threads_list.");
		return val_result;
	}
	else
	{
		val_result = pthread_create(&thread_key,NULL,(void*)tp_slave_thread_handle_func \
					,temp_thread_node);
		if(SYSLOG_SUCCESS != val_result)
		{
			SYSLOG_TRANSPORT_ERROR_LOGGING("Can't create slave thread");
			tp_rm_empty_item_from_ll_func(g_threads_list,temp_thread_node);
			val_result = SYSLOG_FALSE;
		}
		else
		{
			temp_thread_node->data_thread.thread_type = SLAVE_THREAD_TYPE;
			temp_thread_node->data_thread.thread_key = thread_key;
			temp_thread_node->data_thread.socket_id = socket_id;
			temp_thread_node->data_thread.client_addr = *client_addr;
			temp_thread_node->data_thread.thread_func = (void*)tp_slave_thread_handle_func;
			temp_thread_node->state_thread = ITEM_STATE_ACTIVE;
		}
	}
	val_result = pthread_join(thread_key,&temp_thread_result);
	if(SYSLOG_SUCCESS != val_result)
	{
		val_result = SYSLOG_FALSE;
		SYSLOG_TRANSPORT_ERROR_LOGGING("Join thread master failure.");
	}
	return val_result;
}
/***********************************************************************
 * FUNCTION NAME: 
 *  tp_init_listenning_thread_func
 *
 * DESCRIPTION: 
 * Initial listening_thread
 *
 * INPUT: 
 *	
 * OUTPUT:
 *	
 * RETURN:
 *	
 * GLOBAL DATA REFERRED:
 *
 * CALLED ROUTINES:
 *
 * NOTES:
 *
 ************************************************************************/
U8 tp_init_listenning_thread_func()
{
	U8 val_result = SYSLOG_FALSE;
	pthread_t thread_key;
	U8 socket_server;
	void *temp_thread_result;
	threads_transport_t *temp_thread_node = SYSLOG_NULL;
	struct sockaddr_in server;
	
	socket_server = socket(AF_INET,SOCK_STREAM,0);
	
	if(SYSLOG_FAILURE == socket_server)
	{
		SYSLOG_TRANSPORT_ERROR_LOGGING("Can't create socket server");
		exit(EXIT_FAILURE);	
	}
	SYSLOG_TRANSPORT_INFO_LOGGING("Create socket id: %d",socket_server);
	
	/*Initial Socket server*/
	server.sin_family = AF_INET;
	server.sin_port = htons(SYSLOG_PORT_LISTEN);
	server.sin_addr.s_addr = INADDR_ANY;
	
	
	
	/*Create a Node on linked-list and this Node will be parameter of slave function*/
	temp_thread_node = tp_add_empty_item_to_ll_func(g_threads_list);

	if(SYSLOG_NULL == temp_thread_node)
	{
		SYSLOG_TRANSPORT_ERROR_LOGGING("Can't Add a Node to g_threads_list for listening thread.");
		return val_result;
	}
	else
	{
		val_result = pthread_create(&thread_key,NULL,(void*)tp_listening_thread_handle_func \
					,temp_thread_node);
		if(SYSLOG_SUCCESS != val_result)
		{
			SYSLOG_TRANSPORT_ERROR_LOGGING("Can't create listening thread");
			tp_rm_empty_item_from_ll_func(g_threads_list,temp_thread_node);
			val_result = SYSLOG_FALSE;
		}
		else
		{
			temp_thread_node->data_thread.thread_type = LISTEN_THREAD_TYPE;
			temp_thread_node->data_thread.thread_key = thread_key;
			temp_thread_node->data_thread.socket_id = socket_server;
			temp_thread_node->data_thread.client_addr = server;
			temp_thread_node->data_thread.thread_func = (void*)tp_listening_thread_handle_func;
			temp_thread_node->state_thread = ITEM_STATE_ACTIVE;
		}
	}
	/*
	val_result = pthread_join(thread_key,&temp_thread_result);

	if(SYSLOG_SUCCESS != val_result)
	{
		val_result = SYSLOG_FALSE;
		SYSLOG_TRANSPORT_ERROR_LOGGING("Join thread master failure.");
	}
	*/
	return val_result;
}
/***********************************************************************
 * FUNCTION NAME: 
 *  tp_listening_thread_handle_func
 * DESCRIPTION: 
 * This function handle for listening thread. 
 *
 * INPUT: 
 *	request_msg_t *req_msg
 * OUTPUT:
 *	
 * RETURN:
 *	val_result
 * GLOBAL DATA REFERRED:
 *
 * CALLED ROUTINES:
 *
 * NOTES:
 *
 ************************************************************************/
U8 tp_listening_thread_handle_func(threads_transport_t *thread_data){
	U8 val_result=SYSLOG_FALSE;
	U32 read_size;
	U8 socket_server,socket_client;
	struct sockaddr_in server,client;
	U8 client_message[2000];
	
	socket_server = thread_data->data_thread.socket_id;
	server = thread_data->data_thread.client_addr;
	
	
	
	/*Handle message at here.*/
	if(bind(socket_server,(struct sockaddr*)&server,sizeof(server)) < 0)
	{
		SYSLOG_TRANSPORT_ERROR_LOGGING("bind failure!");
	}
	else
	{
		SYSLOG_TRANSPORT_INFO_LOGGING("bind done !");
		listen(socket_server,200);
		SYSLOG_TRANSPORT_INFO_LOGGING("waiting for incoming connection ...");
			
		while(1)
		{
			socket_client = accept(socket_server,(struct sockaddr*)&client,(socklen_t*)sizeof(struct sockaddr_in));
			
			if(socket_client<0){
				SYSLOG_TRANSPORT_ERROR_LOGGING("Accept Failure\n");
				exit(EXIT_FAILURE);
			}
			else
			{
				SYSLOG_TRANSPORT_INFO_LOGGING("Accept successful\n");
				/*Send request create a connection_thread for this connection*/
				tp_create_slave_thread_func(socket_client,&client);
				/*
				//Temp code
				while((read_size = recv(socket_client,client_message,2000,0)) > 0)
				{
				}
				if(read_size == 0)
				{
					printf("Client Disconnected\n");
					fflush(stdout);
				}
				else
				{
					if(read_size==-1){
						printf("ERROR:Recv Failure!\n");
						}
						}
					*/
			}
		}
	}
	while(1){}
	return val_result;
}
/***********************************************************************
 * FUNCTION NAME: 
 *  tp_master_thread_handler_func
 * DESCRIPTION:
 *  This function handle for master thread. Master thread will
 *  monitor TASKLIST. if have any request which was sent to TASKLIST.
 *  Master thread will receive request and execute requests.
 *
 * INPUT: 
 *	request_msg_t *req_msg
 * OUTPUT:
 *	
 * RETURN:
 *
 * GLOBAL DATA REFERRED:
 *
 * CALLED ROUTINES:
 *
 * NOTES:
 *
 ************************************************************************/
void tp_master_thread_handler_func(thread_info_t *thread_data){
	U8 val_result=SYSLOG_FALSE;
	/*Create Listening_thread*/

	tp_init_listenning_thread_func();

	tp_list_all_thread_into_ll_func();

	while(1)
	{
		printf("A");
	}
}
/***********************************************************************
 * FUNCTION NAME: 
 *  tp_slave_thread_handle_func
 * DESCRIPTION:
 *	Function is handled-function of slave-thread.
 * INPUT: 
 *	request_msg_t *req_msg
 * OUTPUT:
 *	
 * RETURN:
 *	val_result
 * GLOBAL DATA REFERRED:
 *
 * CALLED ROUTINES:
 *
 * NOTES:
 *
 ************************************************************************/
U8 tp_slave_thread_handle_func(thread_info_t *thread_info){
	while(1){}
	exit(EXIT_SUCCESS);
}
/***********************************************************************
 * FUNCTION NAME: 
 *  main
 * DESCRIPTION:
 *	Begin of Transport Layer
 * INPUT: 
 *	U32 argc
 *	U8 **argv
 * OUTPUT:
 *	
 * RETURN:
 *	val_result
 * GLOBAL DATA REFERRED:
 *
 * CALLED ROUTINES:
 *	init_master_thread_func()
 * NOTES:
 *
 ************************************************************************/
U32 main(U32 argc,U8 **argv)
{
	tp_init_master_thread_func();
	exit(EXIT_SUCCESS);
}

